package com.wali.modules.bil.service;

import com.wali.common.ccp.execl.CcpExcelReport;
import com.wali.common.ccp.page.CcpPagination;
import com.wali.common.enums.ErrorCodeEnum;
import com.wali.modules.bil.bo.BilExpressBO;
import com.wali.modules.bil.bo.BilGoodsBO;
import com.wali.modules.bil.dao.IBilExpressDao;
import com.wali.modules.bil.dao.IBilGoodsDao;
import com.wali.modules.bil.dao.IBilLogisticsDao;
import com.wali.modules.bil.enums.BilLogisticsEnums;
import com.wali.modules.bil.enums.BilOperateEnums;
import com.wali.modules.bil.vo.BilExpressVO;
import com.wali.modules.bil.vo.BilGoodsVO;
import com.wali.modules.bil.vo.BilLogisticsVO;
import com.wali.modules.usr.bo.UsrReceiverBO;
import com.wali.modules.usr.bo.UsrSenderBO;
import com.wali.modules.usr.dao.IUsrReceiverDao;
import com.wali.modules.usr.dao.IUsrSenderDao;
import com.wali.modules.usr.vo.UsrReceiverVO;
import com.wali.modules.usr.vo.UsrSenderVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author walixu
 * @ClassName com.wali.modules.bil.service
 * @Description 运单信息service类
 * @email wali.xu@kpmg.com
 * @date 20/01/2019 3:45 下午
 */
@Service
public class BilExpressService {

    private static Logger logger = LoggerFactory.getLogger(BilExpressService.class);

    @Autowired
    private IBilExpressDao iBilExpressDao;

    @Autowired
    private IUsrReceiverDao iUsrReceiverDao;

    @Autowired
    private IUsrSenderDao iUsrSenderDao;

    @Autowired
    private IBilGoodsDao iBilGoodsDao;

    @Autowired
    private IBilLogisticsDao iBilLogisticsDao;

    /**
     * 当天运单截止目前总数量
     */
    private int todayExpressCount = 0;

    /**
     * 运单状态维护
     */
    private Map<String, Integer[]> bilStatus = new HashMap() {{
        this.put("create", new Integer[]{1});
        this.put("pickup", new Integer[]{2, 3, 31, 4});
        this.put("shipped", new Integer[]{5, 6, 7, 8, 9, 10});
        this.put("received", new Integer[]{11, 12, 13});
        this.put("finished", new Integer[]{14});
    }};

    /**
     * @param
     * @return
     * @throws
     * @Title saveBilExpress
     * @Description 保存运单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveBilExpress(BilExpressBO bilExpress, UsrReceiverBO usrReceiver, UsrSenderBO usrSender, List<BilGoodsBO> goodsList) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);

        // 检查收件人信息是否已经存在,通过验证身份证+手机号
        updateUsrReceiver(bilExpressVO, usrReceiver);

        // 检查发件人信息是否已经存在，验证手机号
        updateUsrSender(bilExpressVO, usrSender);

        String waybillNo = createWaybilNo();// 创建运单号

        // 新增运单信息
        bilExpressVO.setWaybillNo(waybillNo);
        bilExpressVO.setOperate(BilOperateEnums.BIL_ONE_CREATE.getOperate());
        if (bilExpressVO.getTotal() != 0) {// 填写了总费用之后，运单状态就改为分店已收件
            bilExpressVO.setState(BilLogisticsEnums.BIL_GETIN_SUCCESS.getState());
        } else {
            bilExpressVO.setState(BilLogisticsEnums.BIL_CREATE_SUCCESS.getState());
        }

        iBilExpressDao.saveBilExpress(bilExpressVO);

        // 新增商品信息
        for (BilGoodsBO temp : goodsList) {
            BilGoodsVO bilGoodsVO = BilGoodsBO.convert(temp);
            bilGoodsVO.setWaybillNo(waybillNo);
            iBilGoodsDao.saveBilGoods(bilGoodsVO);
        }

        // 新增物流信息
        BilLogisticsVO bilLogisticsVO = new BilLogisticsVO();
        bilLogisticsVO.setWaybillNo(waybillNo);
        bilLogisticsVO.setState(BilLogisticsEnums.BIL_CREATE_SUCCESS.getState());
        bilLogisticsVO.setDescription(BilLogisticsEnums.BIL_CREATE_SUCCESS.getMessage());
        iBilLogisticsDao.saveBilLogistics(bilLogisticsVO);

        if (bilExpressVO.getTotal() != 0) {// 如果填写了总费用，就新增一条运单已揽收的状态信息
            bilLogisticsVO.setState(BilLogisticsEnums.BIL_GETIN_SUCCESS.getState());
            bilLogisticsVO.setDescription(BilLogisticsEnums.BIL_GETIN_SUCCESS.getMessage());
            iBilLogisticsDao.saveBilLogistics(bilLogisticsVO);
        }
    }


    /**
     * @param
     * @return
     * @throws
     * @Title updateBilExpress
     * @Description 更新运单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateBilExpress(BilExpressBO bilExpress, UsrReceiverBO usrReceiver, UsrSenderBO usrSender, List<BilGoodsBO> goodsList) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);

        BilExpressVO tempExpress = iBilExpressDao.getBilExpress(bilExpressVO);

        // 检查收件人信息是否已经存在,通过验证身份证+手机号
        usrReceiver.setId(0);
        updateUsrReceiver(bilExpressVO, usrReceiver);

        // 检查发件人信息是否已经存在，验证手机号
        usrSender.setId(0);
        updateUsrSender(bilExpressVO, usrSender);

        // 更新运单基本信息
        if (tempExpress != null && tempExpress.getTotal() == 0 && bilExpressVO.getTotal() != 0) {// 如果填写了总费用，就新增一条运单已揽收的状态信息
            bilExpressVO.setState(BilLogisticsEnums.BIL_GETIN_SUCCESS.getState());
        }
        iBilExpressDao.updateBilExpress(bilExpressVO);

        // 删除旧商品信息
        BilGoodsVO tempBilGoods = new BilGoodsVO();
        tempBilGoods.setWaybillNo(bilExpress.getWaybillNo());
        iBilGoodsDao.deleteBilGoods(tempBilGoods);

        // 新增新商品信息
        for (BilGoodsBO temp : goodsList) {
            BilGoodsVO bilGoodsVO = BilGoodsBO.convert(temp);
            bilGoodsVO.setWaybillNo(bilExpress.getWaybillNo());
            iBilGoodsDao.saveBilGoods(bilGoodsVO);
        }

        if (tempExpress != null && tempExpress.getTotal() == 0 && bilExpressVO.getTotal() != 0) {// 如果填写了总费用，那就新增运单已揽收的状态信息
            BilLogisticsVO bilLogisticsVO = new BilLogisticsVO();
            bilLogisticsVO.setWaybillNo(bilExpress.getWaybillNo());
            bilLogisticsVO.setState(BilLogisticsEnums.BIL_GETIN_SUCCESS.getState());
            bilLogisticsVO.setDescription(BilLogisticsEnums.BIL_GETIN_SUCCESS.getMessage());
            iBilLogisticsDao.saveBilLogistics(bilLogisticsVO);
        }
    }

    /**
     * @param
     * @return
     * @throws
     * @Title listBilExpress
     * @Description 查询符合条件的运单信息
     */
    public CcpPagination<BilExpressVO> listBilExpress(BilExpressBO bilExpress, List<Integer> stateIntList, int page, int limit) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);

        List<BilExpressVO> bilExpressList = iBilExpressDao.listBilExpress(bilExpressVO, stateIntList, page, limit);
        int count = iBilExpressDao.countBilExpress(bilExpressVO, stateIntList);

        CcpPagination pagination = new CcpPagination();
        pagination.setData(bilExpressList);
        pagination.setCode(ErrorCodeEnum.SUCCESS_CODE.getCode());
        pagination.setMsg(ErrorCodeEnum.SUCCESS_CODE.getMessage());
        pagination.setCount(count);

        return pagination;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title batchUpdateBilExpress
     * @Description 批量更新运单信息
     */
    public int batchUpdateBilExpress(List<BilExpressVO> bilExpressList) {
        return iBilExpressDao.batchUpdateBilExpress(bilExpressList);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title batchUpdateBilExpressState
     * @Description 批量更新运单状态
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchUpdateBilExpressState(String waybillNos, int state) {
        String[] waybillNoArr = waybillNos.split(",");
        List<String> waybillNoList = Arrays.asList(waybillNoArr);

        List<BilLogisticsVO> bilLogisticsList = new ArrayList<>();
        for (String waybillNo : waybillNoList) {
            BilLogisticsVO temp = new BilLogisticsVO();
            temp.setWaybillNo(waybillNo);
            temp.setState(state);
            temp.setDescription(BilLogisticsEnums.getMessage(state));
            bilLogisticsList.add(temp);
        }
        iBilLogisticsDao.batchSaveBilLogistics(bilLogisticsList);

        return iBilExpressDao.batchUpdateBilExpressState(waybillNoList, state);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title countTodayExpressCount
     * @Description 统计当前截止目前运单总数
     */
    @PostConstruct
    @Scheduled(cron = "0 0 0 * * ?")
    public void countTodayExpressCount() {
        logger.info("countTodayExpressCount start");

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String date = dateFormat.format(new Date());

        BilExpressVO bilExpressVO = new BilExpressVO();
        bilExpressVO.setCreateTime(date);
        todayExpressCount = iBilExpressDao.countBilExpress(bilExpressVO, null);

        logger.info("countTodayExpressCount end : todayExpressCount = " + todayExpressCount);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title deleteBilExpress
     * @Description 删除指定运单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public int deleteBilExpress(BilExpressBO bilExpress) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);

        // 删除运单信息
        int count = iBilExpressDao.deleteBilExpress(bilExpressVO);

        // 删除运单的物品信息
        BilGoodsVO bilGoodsVO = new BilGoodsVO();
        bilGoodsVO.setWaybillNo(bilExpressVO.getWaybillNo());
        iBilGoodsDao.deleteBilGoods(bilGoodsVO);

        // 删除运单的物流信息
        BilLogisticsVO bilLogisticsVO = new BilLogisticsVO();
        bilLogisticsVO.setWaybillNo(bilExpressVO.getWaybillNo());
        iBilLogisticsDao.deleteBilLogistics(bilLogisticsVO);

        return count;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title countBilExpress
     * @Description 统计符合条件的运单信息总数
     */
    public int countBilExpress(BilExpressBO bilExpress, List<Integer> stateIntList) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);
        return iBilExpressDao.countBilExpress(bilExpressVO, stateIntList);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title excelBilReportTo
     * @Description 导出符合条件的运单信息
     */
    public CcpExcelReport exportBilExpressTo(BilExpressBO bilExpress) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        if(StringUtils.isBlank(bilExpressVO.getStartDate()) || StringUtils.isBlank(bilExpressVO.getEndDate())) {

            Calendar theCa = Calendar.getInstance();
            theCa.setTime(new Date());
            String endDate = format.format(theCa.getTime());

            theCa.add(theCa.DATE, -30);
            String startDate = format.format(theCa.getTime());

            bilExpressVO.setStartDate(startDate);
            bilExpressVO.setEndDate(endDate);
        }

        List<BilExpressVO> bilExpressList = iBilExpressDao.listBilExpressTo(bilExpressVO);

        String[] header = new String[]{"进出口日期", "企业运单号",
                "商品序列号", "分运单毛重", "箱件数", "收件人姓名", "收件人地址", "收件人电话",
                "收件人证件号码", "数量", "收件人省", "收件人市", "收件人区", "中通单号", "批次号", "状态"};

        CcpExcelReport excelReport = new CcpExcelReport(null, header);

        if (bilExpressList.size() > 0) {
            for (BilExpressVO temp : bilExpressList) {
                String addr = (temp.getReceiverProvince() + temp.getReceiverCity() + temp.getReceiverAddr()).replaceAll(" ","");

                Row row = excelReport.addRow();
                excelReport.addCell(row, 0, temp.getCreateTime());
                excelReport.addCell(row, 1, temp.getWaybillNo());
                excelReport.addCell(row, 2, temp.getBarcode());
                excelReport.addCell(row, 3, temp.getChargeWeight());
                excelReport.addCell(row, 4, 1);
                excelReport.addCell(row, 5, temp.getReceiverName());
                excelReport.addCell(row, 6, addr);
                excelReport.addCell(row, 7, temp.getReceiverTelphone());
                excelReport.addCell(row, 8, temp.getIdCard());
                excelReport.addCell(row, 9, temp.getCount());
                excelReport.addCell(row, 10, temp.getReceiverProvince());
                excelReport.addCell(row, 11, temp.getReceiverCity());
                excelReport.addCell(row, 12, "");
                excelReport.addCell(row, 13, temp.getExpressNo());
                excelReport.addCell(row, 14, temp.getBatchNo());
                excelReport.addCell(row, 15, BilLogisticsEnums.getMessage(temp.getState()));
            }
        }
        return excelReport;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title exportBilExpress
     * @Description 导出符合条件的运单信息
     */
    public CcpExcelReport exportBilExpress(BilExpressBO bilExpress, List<Integer> statesList) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);

        List<BilExpressVO> bilExpressList = iBilExpressDao.listBilExpress(bilExpressVO, statesList,0, 0);

        // 0 - 11
        String[] header = new String[]{"订单号", "运费",
                "收件人姓名", "收件人电话", "收件人省", "收件人市", "收件人区", "收件人地址", "收件人单位",
                "品名", "数量", "备注", "重量", "条形码", "品牌", "品名", "规格", "单价"};
        CcpExcelReport excelReport = new CcpExcelReport(null, header);

        if (bilExpressList.size() > 0) {
            int index = 0;
            for (final BilExpressVO temp : bilExpressList) {
                index++;
                if (index <= 1000) {
                    List<BilGoodsVO> bilGoodsList = iBilGoodsDao.listBilGoods(new BilGoodsVO() {{
                        this.setWaybillNo(temp.getWaybillNo());
                    }});

                    for (BilGoodsVO tempGood : bilGoodsList) {
                        Row row = excelReport.addRow();
                        excelReport.addCell(row, 0, temp.getWaybillNo());
                        excelReport.addCell(row, 1, temp.getTotal());
                        excelReport.addCell(row, 2, temp.getReceiverName());
                        excelReport.addCell(row, 3, temp.getReceiverTelphone());
                        excelReport.addCell(row, 4, temp.getReceiverProvince());
                        excelReport.addCell(row, 5, temp.getReceiverCity());
                        excelReport.addCell(row, 7, temp.getReceiverAddr());

                        StringBuilder brand = new StringBuilder();
                        for (int i = 0; i < bilGoodsList.size(); i++) {
                            BilGoodsVO tempGoods = bilGoodsList.get(i);
                            if ((i + 1) == bilGoodsList.size()) {
                                brand.append(tempGoods.getBrand() + tempGoods.getName() + tempGoods.getSpecs() + "*" + tempGoods.getCount());
                            } else {
                                brand.append(tempGoods.getBrand() + tempGoods.getName() + tempGoods.getSpecs() + "*" + tempGoods.getCount() + ",");
                            }
                        }

                        excelReport.addCell(row, 9, brand);
                        excelReport.addCell(row, 11, temp.getIdCard());
                        excelReport.addCell(row, 12, temp.getChargeWeight());
                        excelReport.addCell(row, 13, tempGood.getBarcode());
                        excelReport.addCell(row, 14, tempGood.getBrand());
                        excelReport.addCell(row, 15, tempGood.getName());
                        excelReport.addCell(row, 16, tempGood.getSpecs());
                        excelReport.addCell(row, 17, tempGood.getPrice());
                    }
                }
            }
        }

        return excelReport;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title
     * @Description 查询指定的运单详细信息
     */
    public BilExpressVO getBilExpress(BilExpressBO bilExpress) {
        BilExpressVO bilExpressVO = BilExpressBO.convert(bilExpress);
        bilExpressVO = iBilExpressDao.getBilExpress(bilExpressVO);
        return bilExpressVO;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title
     * @Description 查询运单的物品信息
     */
    public List<BilGoodsVO> listBilGoods(BilGoodsBO bilGoods) {
        BilGoodsVO bilGoodsVO = BilGoodsBO.convert(bilGoods);
        List<BilGoodsVO> bilGoodsList = iBilGoodsDao.listBilGoods(bilGoodsVO);
        return bilGoodsList;
    }

    /**
     * @param
     * @return
     * @throws
     * @Title
     * @Description 通过id查询运单的信息列表
     */
    public List<BilExpressVO> listBilExpressByIds(List<Integer> idsList, String storeCode) {
        return iBilExpressDao.listBilExpressByIds(idsList, storeCode);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title
     * @Description 通过id查询运单的物品信息列表
     */
    public List<BilGoodsVO> listBilGoodsByExpressIds(List<Integer> idsList) {
        return iBilGoodsDao.listBilGoodsByExpressId(idsList);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title createWaybilNo
     * @Description 创建运单号
     */
    private synchronized String createWaybilNo() {
        String waybillNoPrefix = "TDC";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMdd");
        String date = dateFormat.format(new Date());

        todayExpressCount++;
        String suffix = "0000" + todayExpressCount;
        return waybillNoPrefix + date + suffix.substring(suffix.length() - 4);
    }

    /**
     * @param
     * @return
     * @throws
     * @Title updateUsrReceiver
     * @Description 更新或新增一条收件人信息
     */
    private void updateUsrReceiver(BilExpressVO bilExpressVO, UsrReceiverBO usrReceiver) {
        // 检查收件人信息是否已经存在,通过验证身份证
        UsrReceiverVO newUsrReceiverVO = UsrReceiverBO.convert(usrReceiver);

        UsrReceiverVO temp = new UsrReceiverVO();
        temp.setTelphone(newUsrReceiverVO.getTelphone());
        temp.setIdCard(newUsrReceiverVO.getIdCard());
        UsrReceiverVO oldUsrReceiverVO = iUsrReceiverDao.getUsrReceiver(temp);
        if (oldUsrReceiverVO == null) {// 收件人信息不存在，那就新增一条
            newUsrReceiverVO.setUserId(bilExpressVO.getUserId());
            iUsrReceiverDao.saveUsrReceiver(newUsrReceiverVO);// 新增收件人信息
            bilExpressVO.setReceiverId(newUsrReceiverVO.getId());
        } else {// 收件人信息已经存在，那就更新
            newUsrReceiverVO.setId(oldUsrReceiverVO.getId());
            iUsrReceiverDao.updateUsrReceiver(newUsrReceiverVO);// 更新收件人信息
            bilExpressVO.setReceiverId(oldUsrReceiverVO.getId());
        }
    }

    /**
     * @param
     * @return
     * @throws
     * @Title
     * @Description 更新或新增一条发件人信息
     */
    private void updateUsrSender(BilExpressVO bilExpressVO, UsrSenderBO usrSender) {
        if (StringUtils.isBlank(usrSender.getSenderTelphone())) {
            return;
        }

        // 检查发件人信息是否已经存在，验证手机号
        UsrSenderVO newUsrSenderVO = UsrSenderBO.convert(usrSender);

        UsrSenderVO temp = new UsrSenderVO();
        temp.setTelphone(newUsrSenderVO.getTelphone());
        UsrSenderVO oldUsrSenderVO = iUsrSenderDao.getUsrSender(newUsrSenderVO);
        if (oldUsrSenderVO == null) {// 收件人信息不存在，那就新增一条
            newUsrSenderVO.setUserId(bilExpressVO.getUserId());
            iUsrSenderDao.saveUsrSender(newUsrSenderVO);
            bilExpressVO.setSenderId(newUsrSenderVO.getId());
        } else {// 收件人信息已经存在，那就更新
            newUsrSenderVO.setId(oldUsrSenderVO.getId());
            iUsrSenderDao.updateUsrSender(newUsrSenderVO);// 更新发件人信息
            bilExpressVO.setSenderId(oldUsrSenderVO.getId());
        }
    }
}
